package cn.hexcloud.dga.governance.assessor.security;

import cn.hexcloud.dga.governance.assessor.Assessor;
import cn.hexcloud.dga.governance.bean.AssessParam;
import cn.hexcloud.dga.governance.bean.GovernanceAssessDetail;
import cn.hexcloud.dga.governance.bean.GovernanceMetric;
import cn.hexcloud.dga.meta.bean.TableMetaInfo;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.permission.FsPermission;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.math.BigDecimal;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;

/**
 * @author jiangdan7
 */
@Component("FILE_ACCESS_PERMISSION")
public class FileAccessPermissionAssessor extends Assessor {
    private List<String> beyondDirPermissionList;
    private List<String> beyondFilePermissionList;

    @Override
    public void checkProblem(GovernanceAssessDetail governanceAssessDetail, AssessParam assessParam) throws Exception {
        // 清空历史数据
        beyondDirPermissionList = new ArrayList<>();
        beyondFilePermissionList = new ArrayList<>();
        // 获取权限阈值
        GovernanceMetric governanceMetric = assessParam.getGovernanceMetric();
        String metricParamsJson = governanceMetric.getMetricParamsJson();
        JSONObject metricParamsJsonObj = JSONObject.parseObject(metricParamsJson);
        String filePermission = metricParamsJsonObj.getString("file_permission");
        String dirPermission = metricParamsJsonObj.getString("dir_permission");

        TableMetaInfo tableMetaInfo = assessParam.getTableMetaInfo();
        String tableFsOwner = tableMetaInfo.getTableFsOwner();
        String tableFsPath = tableMetaInfo.getTableFsPath();
        getPermissionInfo(tableFsPath, tableFsOwner, filePermission, dirPermission);
        if (beyondFilePermissionList.size() != 0 || beyondDirPermissionList.size() != 0) {
            governanceAssessDetail.setAssessScore(BigDecimal.ZERO);
            StringBuilder joinSb = new StringBuilder();
            if (beyondDirPermissionList.size() > 0) {
                joinSb.append("超出权限的目录:\n" + StringUtils.join(beyondDirPermissionList, ",\n"));
            }
            if (beyondFilePermissionList.size() > 0) {
                joinSb.append("超出权限的文件:\n" + StringUtils.join(beyondFilePermissionList, ",\n"));
            }
            governanceAssessDetail.setAssessProblem(joinSb.toString().substring(0, Math.min(joinSb.toString().length(), 2000)));
        }
    }

    private void getPermissionInfo(String path, String tableFsOwner, String filePermission, String dirPermission) throws Exception {
        FileSystem fileSystem = FileSystem.get(new URI(path), new Configuration(), tableFsOwner);
        if (fileSystem.exists(new Path(path))) {
            FileStatus[] subFileStatus = fileSystem.listStatus(new Path(path));
            JudgePermission(fileSystem, filePermission, dirPermission, subFileStatus);
        }
    }

    private void JudgePermission(FileSystem fileSystem, String filePermission, String dirPermission, FileStatus[] fileStatus) throws IOException {
        for (FileStatus fileState : fileStatus) {
            FsPermission curPermission = fileState.getPermission();
            if (fileState.isDirectory()) {
                if (dirOrFilePermissionCompareBeyond(curPermission, dirPermission)) {
                    beyondDirPermissionList.add(fileState.getPath().toString());
                }
                FileStatus[] subFileStatus = fileSystem.listStatus(fileState.getPath());
                JudgePermission(fileSystem, filePermission, dirPermission, subFileStatus);
            } else {
                if (dirOrFilePermissionCompareBeyond(curPermission, filePermission)) {
                    beyondFilePermissionList.add(fileState.getPath().toString());
                }
            }
        }
    }

    private boolean dirOrFilePermissionCompareBeyond(FsPermission curPermission, String permission) {
        int userPermission = Integer.parseInt(permission.substring(0, 1));
        int groupPermission = Integer.parseInt(permission.substring(1, 2));
        int otherPermission = Integer.parseInt(permission.substring(2, 3));
        return (curPermission.getUserAction().ordinal() > userPermission || curPermission.getGroupAction().ordinal() > groupPermission || curPermission.getOtherAction().ordinal() > otherPermission);
    }
}
